package com.company.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;

import java.util.Date;

/**
 * @description: 接受处理响应客户端ws请求的核心处理类
 * @author: ruoan
 * @date: 2020/12/28 22:03
 */
public class MyWebSocketHandler extends SimpleChannelInboundHandler<Object> {


    private WebSocketServerHandshaker handshaker ;
    private static final String WS_URL = "ws://localhost:8888/websocket";

    // client and server connect
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        NettyConfig.group.add(ctx.channel());
        System.out.println("链接开启");
    }
    // client and server disconnect
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        NettyConfig.group.remove(ctx.channel());
        System.out.println("链接关闭");
    }
    // server 接收 client 的数据 end 后
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
        System.out.println("channelReadComplete");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
        System.out.println("exceptionCaught");
    }





    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
        System.out.println("channelRead0");

        //处理客户端向服务端发起http握手请求的业务
        if (o instanceof FullHttpRequest) {
            handHttpRequest(channelHandlerContext,(FullHttpRequest) o);
        }else if(o instanceof WebSocketFrame){
            //
            handWebSocketFrame(channelHandlerContext, (WebSocketFrame) o);
        }
    }


    private void handWebSocketFrame(ChannelHandlerContext ctx,WebSocketFrame frame){
        if (frame instanceof CloseWebSocketFrame) {
            handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
        }
        // 判断是否ping消息
        if (frame instanceof PingWebSocketFrame) {
            ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
        }
        // 判断是否二进制消息
        if (!(frame instanceof TextWebSocketFrame)) {
            System.out.println("目前我们不支持二进制消息");
            throw new RuntimeException("目前我们不支持二进制消息");
        }
        String request = ((TextWebSocketFrame) frame).text();
        System.out.println("服务端收到客户端的消息======>" + request);
        TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame(new Date().toString() + " "
                + ctx.channel().id()
                + " ===>" + request);

        //群发功能
        NettyConfig.group.writeAndFlush(textWebSocketFrame);
    }


    /**
     * 处理客户端向服务端发起http握手请求的业务
     * @param ctx
     * @param request
     */
    private void handHttpRequest(ChannelHandlerContext ctx,FullHttpRequest request) {
        if (!request.getDecoderResult().isSuccess() || !"websocket".equalsIgnoreCase(request.headers().get("Upgrade"))) {
            //
            sendHttpResponse(ctx, request, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
        }

        WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(WS_URL,null,false);
        handshaker = wsFactory.newHandshaker(request);
        if (handshaker == null) {
            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
        } else{
            handshaker.handshake(ctx.channel(),request);
        }
    }


    private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest request, DefaultFullHttpResponse response){
        if (response.getStatus().code() != 200) {
            ByteBuf buf = Unpooled.copiedBuffer(response.getStatus().toString(), CharsetUtil.UTF_8);
            response.content().writeBytes(buf);
            buf.release();
        }

        ChannelFuture f = ctx.channel().writeAndFlush(response);
        if (response.getStatus().code() != 200) {
            f.addListener(ChannelFutureListener.CLOSE);
        }
    }

}


